<?php
use yesf\Yesf;
?>
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>APIGateway管理面板</title>
	<link rel="stylesheet" href="https://fonts.geekzu.org/css?family=Roboto:300,400,500,700,400italic|Material+Icons" />
	<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vue-material@1.0.0-beta-10.2/dist/vue-material.min.css" />
	<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vue-material@1.0.0-beta-10.2/dist/theme/default.css" />
	<style>
	#app .md-app {
		min-height: 100vh;
	}
	.md-dialog {
		width: 90%;
		max-width: 800px;
	}
	.md-button.with-icon .md-icon {
		margin-right: 6px;
	}
	.config-form {
		padding-top: 6px;
		padding-left: 10px;
		padding-right: 10px;
	}
	</style>
	<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.min.js"></script>
	<script src="https://cdn.jsdelivr.net/npm/vue-material@1.0.0-beta-10.2/dist/vue-material.min.js"></script>
</head>
<body>
	<div id="app">
		<md-app md-waterfall md-mode="fixed">
			<md-app-toolbar class="md-primary">
				<span class="md-title">APIGateway管理面板</span>
			</md-app-toolbar>
			<md-app-drawer md-permanent="full">
				<md-list>
					<md-list-item @click="switchPage('config')">
						<md-icon>settings</md-icon>
						<span class="md-list-item-text">设置</span>
					</md-list-item>
					<md-list-item @click="switchPage('app')">
						<md-icon>repeat</md-icon>
						<span class="md-list-item-text">应用管理</span>
					</md-list-item>
					<md-list-item @click="switchPage('service')">
						<md-icon>apps</md-icon>
						<span class="md-list-item-text">服务管理</span>
					</md-list-item>
					<md-list-item @click="loginout">
						<md-icon>exit_to_app</md-icon>
						<span class="md-list-item-text">退出登录</span>
					</md-list-item>
				</md-list>
			</md-app-drawer>
			<md-app-content v-show="activePage == 'config'">
				<md-button class="with-icon" @click="loadConfig"><md-icon>refresh</md-icon>刷新</md-button>
				<md-button class="with-icon" @click="saveConfig"><md-icon>save</md-icon>保存</md-button>
				<md-button class="with-icon" @click="changePassword"><md-icon>vpn_key</md-icon>修改密码</md-button>
				<div class="config-form">
					<md-field v-for="c of config" :key="c.id">
						<label :for="`config_${c.id}`">{{c.name}}</label>
						<md-input :id="`config_${c.id}`" v-model="c.value"/>
					</md-field>
				</div>
			</md-app-content>
			<md-app-content v-show="activePage == 'app'">
				<md-button class="with-icon" @click="loadApp"><md-icon>refresh</md-icon>刷新</md-button>
				<md-button class="with-icon" @click="editApp(null)"><md-icon>create_new_folder</md-icon>新建</md-button>
				<md-table>
					<md-table-row>
						<md-table-head md-numeric>ID</md-table-head>
						<md-table-head>名称</md-table-head>
						<md-table-head>操作</md-table-head>
					</md-table-row>
					<md-table-row v-for="a of app" :key="a.id">
						<md-table-cell md-numeric>{{a.id}}</md-table-cell>
						<md-table-cell>{{a.name}}</md-table-cell>
						<md-table-cell>
							<md-button class="with-icon" @click="showSecret(a.secret)"><md-icon>vpn_key</md-icon>查看Secret</md-button>
							<md-button class="with-icon" @click="editPermission(a)"><md-icon>edit</md-icon>权限</md-button>
							<md-button class="with-icon" @click="editApp(a)"><md-icon>edit</md-icon>编辑</md-button>
							<md-button class="with-icon" @click="delApp(a)"><md-icon>delete</md-icon>删除</md-button>
						</md-table-cell>
					</md-table-row>
				</md-table>
			</md-app-content>
			<md-app-content v-show="activePage == 'service'">
				<md-button class="with-icon" @click="loadService"><md-icon>refresh</md-icon>刷新</md-button>
				<md-field>
					<md-select v-model="serviceSelect" @md-selected="onServiceChange">
						<md-option v-for="s of service" :value="s.id">{{s.name}}</md-option>
					</md-select>
				</md-field>
				<md-table>
					<md-table-row>
						<md-table-head md-numeric>ID</md-table-head>
						<md-table-head>服务ID</md-table-head>
						<md-table-head>IP</md-table-head>
						<md-table-head>端口</md-table-head>
						<md-table-head>权重</md-table-head>
					</md-table-row>
					<md-table-row v-for="s of server" :key="s.id">
						<md-table-cell md-numeric>{{s.id}}</md-table-cell>
						<md-table-cell>{{s.service}}</md-table-cell>
						<md-table-cell>{{s.ip}}</md-table-cell>
						<md-table-cell>{{s.port}}</md-table-cell>
						<md-table-cell>{{s.weight}}</md-table-cell>
					</md-table-row>
				</md-table>
			</md-app-content>
		</md-app>
		<md-dialog :md-active="showLogin" :md-close-on-esc="false" :md-click-outside-to-close="false">
			<md-dialog-title>登录</md-dialog-title>
			<div style="text-align:center" v-show="status == 0"><md-progress-spinner md-mode="indeterminate" ></md-progress-spinner></div>
			<md-dialog-content v-show="status == 1">
				<md-field>
					<label>密码</label>
					<md-input v-model="password"></md-input>
				</md-field>
			</md-dialog-content>
			<md-dialog-actions v-show="status == 1">
				<md-button class="md-primary" @click="tryLogin">登录</md-button>
			</md-dialog-actions>
		</md-dialog>
		<md-dialog-prompt
			:md-active.sync="newPassword.show"
			v-model="newPassword.value"
			md-title="修改密码"
			md-input-maxlength="30"
			md-input-placeholder="输入新密码"
			@md-confirm="changePasswordSubmit">
		</md-dialog-prompt>
		<md-dialog :md-active.sync="edit_app.show">
			<md-dialog-title>编辑/新建</md-dialog-title>
			<md-dialog-content>
				<md-field v-show="edit_app.id != -1">
					<label>ID</label>
					<md-input v-model="edit_app.id" disabled></md-input>
				</md-field>
				<md-field>
					<label>名称</label>
					<md-input v-model="edit_app.name"></md-input>
				</md-field>
				<md-field>
					<label>AppSecret</label>
					<md-input v-model="edit_app.secret"></md-input>
				</md-field>
			</md-dialog-content>
			<md-dialog-actions>
				<md-button class="md-primary" @click="edit_app.show = false">取消</md-button>
				<md-button class="md-primary" @click="editAppSave">保存</md-button>
			</md-dialog-actions>
		</md-dialog>
		<md-dialog-alert
			:md-active.sync="show_secret.show"
			:md-content="show_secret.content" />
		<md-snackbar md-position="center" :md-duration="3000" :md-active.sync="toast.show" md-persistent>
			<span>{{toast.message}}</span>
		</md-snackbar>
	</div>
	<script>
	Vue.use(VueMaterial.default);

	function Api(param) {
		return new Promise(resolve => {
			const fetchParam = {
				method: param.post ? 'POST' : 'GET',
				headers: {
					'X-Admin-Password': sessionStorage.getItem('api_admin')
				}
			};
			let url = '/' + param.url;
			if (param.query) {
				url += '?' + (new URLSearchParams(param.query)).toString();
			}
			if (fetchParam.method === 'POST') {
				fetchParam.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
				const formBody = [];
				for (const property in param.post) {
					const encodedKey = encodeURIComponent(property);
					const encodedValue = encodeURIComponent(param.post[property]);
					formBody.push(encodedKey + "=" + encodedValue);
				}
				fetchParam.body = formBody.join("&");
			}
			fetch(url, fetchParam)
			.then(r => r.json())
			.then(resolve);
		})
	}

	new Vue({
		el: '#app',
		data: function() {
			return {
				status: 0,
				activePage: "config",
				password: "",
				config: [],
				app: [],
				service: [],
				server: [],
				serviceSelect: "",
				toast: {
					show: false,
					message: ""
				},
				newPassword: {
					show: false,
					value: ""
				},
				edit_app: {
					show: false,
					name: "",
					id: -1,
					secret: ""
				},
				show_secret: {
					show: false,
					content: ""
				}
			};
		},
		computed: {
			showLogin: function() {
				return this.status < 2;
			}
		},
		methods: {
			showToast: function(msg) {
				this.toast.message = msg;
				this.toast.show = true;
			},
			switchPage: function(name) {
				this.activePage = name;
			},
			tryLogin: function() {
				const _this = this;
				_this.status = 0;
				Api({
					url: 'admin/index/login',
					post: {
						password: this.password
					}
				})
				.then(r => {
					if (r.success) {
						sessionStorage.setItem('api_admin', r.password);
						_this.status = 2;
						_this.showToast('登录成功');
					} else {
						_this.status = 1;
						_this.showToast(r.error);
					}
				});
			},
			loadConfig: function() {
				const _this = this;
				Api({
					url: 'admin/config/list'
				})
				.then(r => {
					if (r.success) {
						_this.config = r.list
					}
				});
			},
			saveConfig: function() {
				const queue = [];
				const _this = this;
				_this.config.forEach(e => {
					queue.push(Api({
						url: 'admin/config/save',
						post: {
							id: e.id,
							value: e.value
						}
					}));
				});
				Promise.all(queue)
				.then(r => {
					_this.showToast('已保存');
				});
			},
			changePassword: function() {
				this.newPassword.show = true;
			},
			changePasswordSubmit: function() {
				const _this = this;
				Api({
					url: 'admin/config/password',
					post: {
						password: _this.newPassword.value
					}
				})
				.then(r => {
					_this.newPassword.value = "";
					if (r.success) {
						sessionStorage.setItem('wechat_admin', r.password);
						_this.showToast('密码修改成功');
					} else {
						_this.showToast(r.error);
					}
				});
			},
			loadApp: function() {
				const _this = this;
				Api({
					url: 'admin/app/list'
				})
				.then(r => {
					if (r.success) {
						_this.app = r.list;
					}
				});
			},
			showSecret: function(secret) {
				this.show_secret.content = secret;
				this.show_secret.show = true;
			},
			editApp: function(app) {
				if (app === null) {
					this.edit_app.id = -1;
					this.edit_app.name = "";
					this.edit_app.secret = "";
				} else {
					this.edit_app.id = app.id;
					this.edit_app.name = app.name;
					this.edit_app.secret = app.secret;
				}
				this.edit_app.show = true;
			},
			editAppSave: function() {
				const _this = this;
				Api({
					url: 'admin/app/save',
					post: _this.edit_app
				})
				.then(r => {
					if (r.success) {
						_this.edit_app.show = false;
						_this.showToast('已保存');
						_this.loadApp();
					}
				})
			},
			delApp: function(app) {
				const _this = this;
				if (confirm(`您确定要删除应用“${app.name}”吗？此操作不可撤销`)) {
					Api({
						url: 'admin/app/del',
						post: {
							id: app.id
						}
					})
					.then(r => {
						if (r.success) {
							_this.showToast(`已删除应用“${app.name}”`);
							_this.loadApp();
						}
					})
				}
			},
			loadService: function() {
				const _this = this;
				Api({
					url: 'admin/service/list'
				})
				.then(r => {
					_this.service = r.list;
				})
			},
			onServiceChange: function() {
				const _this = this;
				Api({
					url: `admin/service/server?id=${_this.serviceSelect}`,
				})
				.then(r => {
					_this.server = r.list;
				})
			},
			loginout: function() {
				sessionStorage.removeItem('api_admin');
				this.status = 1;
			}
		},
		mounted: function() {
			const _this = this;
			//检查登录状态
			Api({
				url: 'admin/status/status'
			})
			.then(r => {
				if (r.success) {
					_this.status = 2;
				} else {
					_this.status = 1;
				}
			})
		}
	});
	</script>
</body>
</html>